﻿using System.Text;
using EmbeddedSharp.Core;
using EmbeddedSharp.Core.Function;
using EmbeddedSharp.Core.Function.Arithmetics;
using EmbeddedSharp.Core.Function.Maths;
using EmbeddedSharp.Core.Function.Logic;

namespace EmbeddedSharp.Core {
    public class CSharpCodeTranslator : IVisitor {

        public string ClassName {
            get;
            set;
        }

        public IFunctionManager FunctionManager {
            get;
            set;
        }

        public CSharpCodeTranslator(IFunctionManager funMgr)
            : this(string.Empty) {
            this.FunctionManager = funMgr;
        }

        public CSharpCodeTranslator(string className) {
            this.ClassName = className;
        }

        #region IVisitor Members

        public virtual object Visit(IdentifierNode node) {
            return node.Value;
        }

        public object Visit(NumberNode node) {
            return node.Value;
        }

        public object Visit(StringNode node) {
            return node.Value;
        }

        public object Visit(SubNode node) {
            object lr = node.Left.Accept(this);
            object rr = node.Right.Accept(this);

            return string.Format("({0} - {1})", lr, rr);
        }

        public object Visit(AddNode node) {
            object lr = node.Left.Accept(this);
            object rr = node.Right.Accept(this);

            return string.Format("({0} + {1})", lr, rr);
        }

        public object Visit(MulNode node) {
            object lr = node.Left.Accept(this);
            object rr = node.Right.Accept(this);

            return string.Format("({0} * {1})", lr, rr);
        }

        public object Visit(DivNode node) {
            object lr = node.Left.Accept(this);
            object rr = node.Right.Accept(this);

            return string.Format("({0} / {1})", lr, rr);
        }

        public object Visit(ModNode node) {
            object lr = node.Left.Accept(this);
            object rr = node.Right.Accept(this);

            return string.Format("({0} % {1})", lr, rr);
        }

        public object Visit(PowerNode node) {
            object lr = node.Left.Accept(this);
            object rr = node.Right.Accept(this);

            return string.Format("Math.Pow({0}, {1})", lr, rr);
        }

        public object Visit(LogNode node) {
            object lr = node.Left.Accept(this);
            object rr = node.Right.Accept(this);

            return string.Format("Math.Log({0}, {1})", lr, rr);
        }

        public virtual object Visit(FuncNode node) {
            StringBuilder buff = new StringBuilder();

            string funcName = Utils.CheckExpression(node.Value);
            buff.Append(funcName).Append("(");
            for (int index = 0; index < node.Parameters.Count; index++) {
                object value = node.Parameters[index].Accept(this);
                buff.Append(value.ToString());
                if (index + 1 < node.Parameters.Count) {
                    buff.Append(",");
                }
            }
            buff.Append(")");

            return buff.ToString();
        }

        public object VisitNode(OperatorNode node, string op) {
            object lr = node.Left.Accept(this);
            object rr = node.Right.Accept(this);

            return string.Format("({0} {1} {2})", lr, op, rr);
        }

        public object Visit(LargerThanNode node) {
            return this.VisitNode(node, ">");
        }

        public object Visit(LessThanNode node) {
            return this.VisitNode(node, "<");
        }

        public object Visit(LargerEqualToNode node) {
            return this.VisitNode(node, ">=");
        }

        public object Visit(LessEqualToNode node) {
            return this.VisitNode(node, "<=");
        }

        public object Visit(EqualNode node) {
            return this.VisitNode(node, "==");
        }

        public object Visit(NotEqualNode node) {
            return this.VisitNode(node, "!=");
        }

        public object Visit(AndNode node) {
            return this.VisitNode(node, "&&");
        }

        public object Visit(OrNode node) {
            return this.VisitNode(node, "||");
        }

        public object Visit(NotNode node) {
            StringBuilder buff = new StringBuilder();

            string l = System.Convert.ToString(node.Operand.Accept(this));

            return buff.Append("(!").Append(l).Append(")").ToString();
        }

        #endregion

        public string Translate(Node root) {
            return System.Convert.ToString(root.Accept(this));
        }
    }
}
